<?php


class Data{

    // Connect to DB. Para cerrar la DB $db=null
    public static function connectDB(){
        $nameDB='nor';
        $host='localhost';
        $user='nor';
        $pass='nornor';

        try{
            $db = new PDO("mysql:host=$host;dbname=$nameDB", $user,$pass);
            $db->setAttribute(PDO::ATTR_ERRMODE,PDO::ERRMODE_EXCEPTION);
        }
        catch(PDOException $e){
            error_log('error de conexión: '.$e->GetMessage());
            
        }
        return $db;
    }
}


class Entry{
	
    public $entry_id;
    public $publisher_id;
    public $title_e;
    public $content_e;
    public $date;
    public $is_rss;

    public function __construct($entry_id){
        $db = Data::connectDB();

        $sql = "SELECT publisher_id, title, content, date, is_rss FROM entries WHERE entry_id=\"$entry_id\"";
        foreach ($db->query($sql) as $row){
            $this->publisher_id = $row['publisher_id']; 
            $this->title_e      = $row['title'];  
            $this->content_e    = $row['content'];  
            $this->date         = $row['date']; 
            $this->is_rss      = $row['is_rss']; 
        } 
        $this->entry_id = $entry_id;
        $db = null;
    }

    public static function new_entry($pub, $title, $content, $date, $is_rss){
        $db = Data::connectDB();

        $title = $db->quote($title);
        $content = $db->quote($content);
        $date = $db->quote($date);
        $is_rss = $db->quote($is_rss);

        $insert_obj = $db->exec("INSERT INTO entries (entry_id, publisher_id, title, content, date, is_rss) VALUES (null, \"$pub->publisher_id\", $title, $content, $date, $is_rss)");
        $entry_id = $db->lastInsertId();
        $db = null;
        return new Entry($entry_id);
    }
    
    public function del_entry($user){
        if ($user->permission->is_admin() or $user->is_writer_of($this)){
            $db = Data::connectDB();
            $db->exec("DELETE FROM entries WHERE entry_id=\"$this->entry_id\"");
            $db = null;
        }
        else{
            throw new Exception("No tiene permisos para eliminar esta entrada. ");
        }
    }


    public static function get_entries(){
        $entries = array();
        $db = Data::connectDB();
        $query = $db->query("SELECT entry_id FROM entries"); 
        $ids = $query->fetchAll();
        foreach ($ids as $id){
            $entries[] = new Entry($id[0]);   
        }
        return $entries;
    }

    public static function get_entries_limit($first, $last){
        $db = Data::connectDB();

        /* Bug de PDO, ver https://bugs.php.net/bug.php?id=44639 
        $first = $db->quote($first);
        $last  = $db->quote($last);
        error_log("SELECT entry_id FROM entries ORDER BY date ASC LIMIT $first, $last"); 
        */

        $value_extract_1 = array();
        $query1 = $db->query("SELECT entry_id FROM entries ORDER BY date DESC LIMIT $first, $last"); 
        $ids = $query1->fetchAll();
        foreach ($ids as $id){
            $value_extract_1[] = new Entry($id[0]);   
        }
        $query2 = $db->query("SELECT entry_id FROM entries"); 
        $value_extract_2 = $query2->rowCount();
        return compact('value_extract_1', 'value_extract_2');
    }

    public static function get_entries_restricted_pub_limit($pubs, $first, $last){

        $value_extract_1  = array();
        $value_extract_2 = 0;
        $pubs_ids = "";
        if (count($pubs) >= 1){
            $db = Data::connectDB();
            $pubs_ids .= "WHERE ";
            foreach ($pubs as $pub){
                $pubs_ids .= "publisher_id=\"$pub->publisher_id\" OR ";
            }
            $pubs_ids = substr($pubs_ids, 0, -4);

            $query1 = $db->query("SELECT entry_id FROM entries $pubs_ids ORDER BY date DESC LIMIT $first, $last"); 
            $ids = $query1->fetchAll();
            foreach ($ids as $id){
                $value_extract_1[] = new Entry($id[0]);   
            }
            $query2 = $db->query("SELECT entry_id FROM entries $pubs_ids"); 
            $value_extract_2 = $query2->rowCount();
            $db = null;
        }
        return compact('value_extract_1', 'value_extract_2');
    }
}

class Publisher{

        public $publisher_id;
        public $name_p;
        public $rss_url; 
        public $url; 
        public $descrip;

    public function __construct($publisher_id){
        $db = Data::connectDB();
        
        $publicher_id = $db->quote($publisher_id);

        $sql = "SELECT name, rss_url, url, description FROM publishers WHERE publisher_id=$publisher_id";
        foreach ($db->query($sql) as $row){
            $this->name_p  = $row['name'];  
            $this->rss_url = $row['rss_url']; 
            $this->url     = $row['url']; 
            $this->descrip = $row['description'];
        }
        $this->publisher_id = $publisher_id;
        $db = null;
    }

    public static function add_publisher($name, $rss_url, $url, $descrip){
        $db = Data::connectDB();

        $name    = $db->quote($name);
        $rss_url = $db->quote($rss_url);
        $url     = $db->quote($url);
        $descrip = $db->quote($descrip);

        $db->exec("INSERT INTO publishers (publisher_id, name, rss_url, url, description) VALUES (null, $name, $rss_url, $url, $descrip) ");
        $publisher_id = $db->lastInsertId();
        // Activar por defcto en todos los usuarios
        foreach (User::get_ids_users() as $user_id){
            $db->exec("INSERT INTO subscription (user_id, publisher_id) VALUES (\"$user_id[0]\", \"$publisher_id\")");
        }
        $db = null;
    }
    
    public static function del_publisher($pub){
        $db = Data::connectDB();
        $db->exec("DELETE FROM publishers WHERE publisher_id=\"$pub->publisher_id\"");
        $db = null;
    }

    public static function get_publisher_by_name($name){
        $id = null;
        $db = Data::connectDB();
        $name = $db->quote($name);
        $sql = "SELECT publisher_id FROM publishers WHERE name=$name";
        foreach( $db->query($sql) as $row){
            $id = $row['publisher_id'];
        }
        return new Publisher($id);
    }

    public static function get_publishers(){
        $ids = null;
        $pubs = array();
        $db = Data::connectDB();
        $publishers = $db->query("SELECT publisher_id FROM publishers"); 
        $ids = $publishers->fetchAll();
        foreach ($ids as $id){
            $id = $id[0];
            $pubs[] = new Publisher($id);
        }
        return $pubs;
    }

    public static function get_publishers_by_user_id($user_id){
        // get publishers array or false if user don't share rss
        $ids = null;
        $pubs = array();
        $db = Data::connectDB();
        foreach ($db->query("SELECT share FROM users WHERE user_id=\"$user_id\"") as $row){ 
            if (!$row['sharing'])
                return null;
        }
        $publishers = $db->query("SELECT publisher_id FROM subscription WHERE user_id=\"$user_id\""); 
        $ids = $publishers->fetchAll();
        foreach ($ids as $id){
            $id = $id[0];
            $pubs[] = new Publisher($id);
        }
        return $pubs;
    }

    public function __tostring(){
        return '' . $this->publisher_id;
    }

}
     

class User{
    public $user_id = null;
    public $sharing = null;

    public function __construct($email, $hash){
        $db = Data::connectDB();

        $email = $db->quote($email);
        $hash  = $db->quote($hash);

        $sql = "SELECT user_id, permission, sharing FROM users WHERE email=$email AND hash=$hash";
        foreach ($db->query($sql) as $row){
            $this->user_id = $row['user_id'];
            $this->permission = new Permissions($row['permission']);
            $this->sharing = $row['sharing'];
        }
        if ($this->user_id == null)
            throw new Exception("No existe la combinación usuario/contraseña dada. ");
        $this->email = $email;
        $this->hash = $hash;

        $db = null;
	}

    public static function add_user($email, $hash){
        $db = Data::connectDB();

        $email = $db->quote($email);
        $hash = $db->quote($hash);

        $checkUser = $db->query("SELECT email FROM users WHERE email=$email");
        if ($checkUser->rowCount() > 0){
            $db = null;
            throw new Exception("La cuenta de correo dada ya existe.");
        }
        else{
            $perm_default = Permissions::SUBSCRIPTOR;
            $db->exec("INSERT INTO users VALUES(null,$email,$hash,\"$perm_default\", 1)");
            $db = null;

            $user = new User($email, $hash);
            $pubs = Publisher::get_publishers();
            foreach ($pubs as $pub){
                $user->change_subscription($pub, true);
            }
        }
    }

    public function del_user($email_user, $hash){
        if ($this->permission->is_admin() or $this->email == $email_user){
            $db = Data::connectDB();

            $email_user = $db->quote($email_user);
            $hash       = $db->quote($hash);

            $db->exec("DELETE FROM users WHERE email=$email_user");
            $db = null;
        }
    }

    public function get_user_by_id($user_id){
        if ($this->permission->is_admin()){
            $db = Data::connectDB();
            $sql = "SELECT email, hash FROM users WHERE user_id=\"$user_id\"";
            foreach ($db->query($sql) as $row){
                return new User($row['email'], $row['hash']);
            }
            $db = null;
        }
    }

    public function get_user_by_email($email){
        if ($this->permission->is_admin()){
            $db = Data::connectDB();
            $email_user = $db->quote($email);
            $sql = "SELECT hash FROM users WHERE email=$email_user";
            foreach($db->query($sql) as $row){
                $id = $row['hash'];
            }
            $db = null;
            return new User($email, $id);
        }
        return null;
    }

    public static function get_ids_users(){
        $ids = null;
        $db = Data::connectDB();
        $publishers = $db->query("SELECT user_id FROM users"); 
        $ids = $publishers->fetchAll();
        $db = null;
        return $ids;
    }

    public static function get_names_users(){
        $names = null;
        $db = Data::connectDB();
        $publishers = $db->query("SELECT email FROM users ORDER BY email ASC"); 
        $names = $publishers->fetchAll();
        $db = null;
        return $names;
    }

    public function get_subscriptions(){
        $subscriptions = array();
        $sql = "SELECT publisher_id FROM subscription WHERE user_id=\"$this->user_id\"";
        $db = Data::connectDB();
        foreach ($db->query($sql) as $row){
            $subscriptions[] = new Publisher($row['publisher_id']);
        }
        $db = null;
        return $subscriptions;
    
    }

    public function get_write_publishers(){
        $write_pub = array();
        $sql = "SELECT publisher_id FROM writer_permissions WHERE user_id=\"$this->user_id\"";
        $db = Data::connectDB();
        foreach ($db->query($sql) as $row){
            $write_pub[] = new Publisher($row['publisher_id']);
        }
        $db = null;
        return $write_pub;
    }

    public function change_sharing($bool){
        $db = Data::connectDB();
        $db->exec("UPDATE users SET sharing=\"$bool\" WHERE user_id=$this->user_id");
        $this->sharing = $bool;
        $db = null;
    }

	public function change_pass($new_hash){
        $db = Data::connectDB();
        $new_hash = $bd->quote($new_hash);
        $email_user = $bd->quote($this->email);
        $hash_user = $bd->quote($this->hash);
        $db->exec("UPDATE users SET hash=$new_hash WHERE email=$this->email AND hash=$this->hash");
        $db = null;
	}

    public function write_entry($pub, $title, $content, $date, $is_rss='false'){
        if ($this->is_writer_of($pub)){
            $c_entry = Entry::new_entry($pub, $title, $content, $date, $is_rss);
            $db = Data::connectDB();
            $db->exec("INSERT INTO entry_writer (user_id, entry_id) VALUES (\"$this->user_id\", \"$c_entry->entry_id\")");
            $db = null; 
        }   
        else{
            throw new Exception("Este usuario no tiene permiso para añadir nueva entrada");
        }
    }

    public function update_entry($update_entry){
        $pub = new Publisher($update_entry->publisher_id);
        if ($this->is_writer_of($pub)){
            $db = Data::connectDB();
            $title = $db->quote($update_entry->title_e);
            $content = $db->quote($update_entry->content_e);
            $date = $db->quote($update_entry->date);
            $db->exec("UPDATE entries SET title=$title, content=$content, date=$date WHERE entry_id=\"$update_entry->entry_id\"");
            $db = null; 
        }   
        else{
            throw new Exception("Este usuario no tiene permiso para modificar este publicador");
        }
    }


	public function change_email($new_email){
        $db = Data::connectDB();
        $new_email = $bd->quote($new_email);
        $email_user = $bd->quote($this->email);
        $hash_user = $bd->quote($this->hash);
        $db->exec("UPDATE users SET email=$new_email WHERE email=$this->email AND hash=$this->hash");
        $db = null;

    }

    public function is_subscripter_to($pub){
        $db = Data::connectDB();
        $query = $db->query("SELECT user_id FROM subscription WHERE user_id=\"$this->user_id\" and publisher_id=\"$pub->publisher_id\"");
        if ($query->rowCount() > 0)
            $bool = true;
        else
            $bool = false;
        return $bool;
    }

    public function is_writer_of($pub){
        $db = Data::connectDB();
        $query = $db->query("SELECT user_id FROM writer_permissions WHERE user_id=\"$this->user_id\" and publisher_id=\"$pub->publisher_id\"");
        if ($query->rowCount() > 0)
            $bool = true;
        else
            $bool = false;
        return $bool;
    }

    public function change_subscription($pub, $bool){
        $db = Data::connectDB();
        if ($bool)
            $db->exec("INSERT INTO subscription (user_id, publisher_id) VALUES (\"$this->user_id\", \"$pub->publisher_id\")");
        else
            $db->exec("DELETE FROM subscription WHERE user_id=\"$this->user_id\" AND publisher_id=\"$pub->publisher_id\"");
        $db = null;
    }

    // ADMIN ONLY
    public function change_permission($email_user, $permission_user){
        if($this->permission->is_admin()){
            $db = Data::connectDB();
            $email_user = $bd->quote($email_user);
            $db::exec("UPDATE permission SET permission=\"$permission_user\" WHERE email=$email_user");
            $db = null;
        }
    }

    public function change_permission_write($user, $pub, $add){
        if ($this->permission->is_admin()){
            $db = Data::connectDB();
            $email = $user->email;
            if ($add){
                $db->exec("INSERT INTO writer_permissions (user_id, publisher_id) VALUES (\"$user->user_id\", \"$pub->publisher_id\")");
                if (!$user->permission->is_writer()){
                    $db->exec("UPDATE users SET permission=" . (Permissions::WRITER | $user->permission->permission) . " WHERE email=$email");

                }    
            }             
            else{
                $db->exec("DELETE FROM writer_permissions WHERE user_id=\"$user->user_id\" AND publisher_id=\"$pub->publisher_id\"");
                if(count($user->get_write_publishers()) < 1 and !$user->permission->is_admin()){
                    $db->exec("UPDATE users SET permission=\"" . (Permissions::SUBSCRIPTOR ^ $user->permission->permission) . "\" WHERE email=$email");
                }
            }
            $db = null;
        }
    }
}


class Permissions{
        const SUBSCRIPTOR   = 0x01;
        const WRITER        = 0x02;
        const ADMIN         = 0x04;
        const ALL           = 0x07;

        public function __construct($int){
            $this->permission = $int;
        }

        public function is_suscriptor(){
                return ($this->permission & Permissions::SUBSCRIPTOR) == Permissions::SUBSCRIPTOR;
        }
        public function is_writer(){
                return ($this->permission & Permissions::WRITER) == Permissions::WRITER;
        }
        public function is_admin(){
                return ($this->permission & Permissions::ADMIN) == Permissions::ADMIN;
        }
}



?>
